#include "bsp_uart.h"

#define TAG "uart_line"

typedef struct {
    uart_port_t uart_num;
    uart_line_callback_t callback;
    void *user_ctx;
    TaskHandle_t task_handle;
    char buffer[UART_LINE_MAX_LEN];
    int index;
} uart_line_ctx_t;

static uart_line_ctx_t *uart_ctxs[UART_NUM_MAX] = {0};

// 串口接收任务
static void uart_line_task(void *arg) {
    uart_line_ctx_t *ctx = (uart_line_ctx_t *)arg;
    uint8_t byte;

    while (1) {
        int len = uart_read_bytes(ctx->uart_num, &byte, 1, pdMS_TO_TICKS(100));
        if (len > 0) {
            if (byte == '\n' || byte == '\r') {
                if (ctx->index > 0) {
                    ctx->buffer[ctx->index] = '\0';
                    if (ctx->callback) {
                        ctx->callback(ctx->buffer, ctx->user_ctx);
                    }
                    ctx->index = 0;
                }
            } else {
                if (ctx->index < UART_LINE_MAX_LEN - 1) {
                    ctx->buffer[ctx->index++] = byte;
                } else {
                    ctx->index = 0;  // overflow, reset
                }
            }
        }
    }
}

esp_err_t uart_line_init(uart_port_t uart_num, int tx_pin, int rx_pin, int baud_rate) {
    if (uart_num >= UART_NUM_MAX) return ESP_ERR_INVALID_ARG;

    uart_config_t config = {
        .baud_rate = baud_rate,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
    };

    ESP_ERROR_CHECK(uart_param_config(uart_num, &config));
    ESP_ERROR_CHECK(uart_set_pin(uart_num, tx_pin, rx_pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
    ESP_ERROR_CHECK(uart_driver_install(uart_num, UART_LINE_MAX_LEN * 2, 0, 0, NULL, 0));

    uart_line_ctx_t *ctx = calloc(1, sizeof(uart_line_ctx_t));
    if (!ctx) return ESP_ERR_NO_MEM;

    ctx->uart_num = uart_num;
    uart_ctxs[uart_num] = ctx;

    xTaskCreate(uart_line_task, "uart_line_task", 2048, ctx, 10, &ctx->task_handle);
    return ESP_OK;
}

void uart_line_register_callback(uart_port_t uart_num, uart_line_callback_t cb, void *user_ctx) {
    if (uart_num >= UART_NUM_MAX || uart_ctxs[uart_num] == NULL) return;
    uart_ctxs[uart_num]->callback = cb;
    uart_ctxs[uart_num]->user_ctx = user_ctx;
}
